package top.malaoshi.webmvc;

import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import top.malaoshi.easy.logging.Log;
import top.malaoshi.easy.logging.LogFactory;
import top.malaoshi.sprout.ResourceBanner;
import top.malaoshi.sprout.aop.ProxyClassResolver;
import top.malaoshi.sprout.ioc.DefaultSingletonBeanRegistry;
import top.malaoshi.webmvc.annotation.check.AnnotationCheck;
import top.malaoshi.webmvc.annotation.check.CheckBeanName;
import top.malaoshi.webmvc.info.ClassInfo;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;

public class AnnotationConfigApplicationContext2 implements ApplicationContext {

    static final Log LOG = LogFactory.getLog(AnnotationConfigApplicationContext2.class);
    {
        new ResourceBanner().printBanner();
    }

    DefaultSingletonBeanRegistry registry = DefaultSingletonBeanRegistry.me();

    public void execute(String packagePath) throws Exception {
        // 读取application配置文件
        ApplicationConfigFileReader reader = new ApplicationConfigFileReader();
        reader.handler();
        // 1 扫描包路径
        ScanClassHandler.me().addPackage(packagePath);
        ScanClassHandler.me().addPackage("org.springframework");
        ScanClassHandler.me().scanAndFilter();
        // 2 解析类和方法
        resolveClass();

        // 判断是否需要设置为代理类
        isProxyClass();
        // 3 校验注解
        checkAnnotation();

        // 4 实例化
        newAllInstance();

        resolverOrder();

        sortClassInfos();

        // 处理@Value注解，将配置文件的数据注入到成员变量中
        ValueAnnotationHandler vah = new ValueAnnotationHandler();
        vah.handle();


        // 执行启动器
        AutoConfigurationImportSelector ssh = new AutoConfigurationImportSelector();
        ssh.handle();

        // 5 初始化bean，注入成员变量、调用@PostConstruct方法、调用@Bean方法 等
        initBean();

        // 6 执行 Runner 接口的类
        executeRunner();
    }




    /**
     * 对ClassInfo进行排序，之后好初始化
     */
    private void sortClassInfos(){
        registry.sortClassInfos(new Comparator<ClassInfo>() {
            @Override
            public int compare(ClassInfo ci1, ClassInfo ci2) {
                int order1=ci1.getOrder();
                int order2=ci2.getOrder();

                return order1 - order2;
            }
        });
    }


    /**
     * 解析 bean 和 method，放入到 beanInfos 中
     * 并且放入到 classInfos
     */
    private void resolveClass()  {
        ClassAndMethodAndFieldResolver classAndMethodAndFieldResolver = new ClassAndMethodAndFieldResolver();

        registry.forEachClasses( clazz -> {
            try {
                ClassInfo classInfo = classAndMethodAndFieldResolver.resolve(clazz);
                if (classInfo != null) {
                    registry.addClassInfo(classInfo);
                }
            }catch (Exception e){
                LOG.error("",e);
            }
        });
    }

    /**
     * 判断是否设置为代理类
     * @throws Exception
     */
    private void isProxyClass() throws Exception {
        registry.forEachClassInfos( classInfo -> {

            ProxyClassResolver.resolve(classInfo);
        });
    }
    /**
     * 校验注解
     */
    private void checkAnnotation() throws Exception {
        // 校验bean的名字
        AnnotationCheck checkBeanName = new CheckBeanName();
        checkBeanName.check();
    }

    private void newAllInstance() throws Exception {
        registry.forEachClassInfos(classInfo -> {
            String beanName = classInfo.getName();
            Object bean = classInfo.getObjectFactory().getObject();
            registry.registerEarlySingletonObject(beanName,bean);
        });


    }

    /**
     * 解析排序
     * @throws IllegalAccessException
     * @throws InstantiationException
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     */
    private void resolverOrder() throws Exception {
        registry.forEachClassInfos(classInfo -> {
            String beanName = classInfo.getName();
            Object bean = registry.getEarlySingletonObject(beanName);

            int order= Ordered.LOWEST_PRECEDENCE;
            Class clazz = classInfo.getClazz();
            Order orderAnn = (Order) clazz.getAnnotation(Order.class);
            if(orderAnn!=null){ //有 order注解
                order = orderAnn.value();
            }else if(Ordered.class.isAssignableFrom(clazz)){ //实现Ordered 接口

                Method getOrder = clazz.getMethod("getOrder");
                order = (Integer)getOrder.invoke(bean);

            }

            classInfo.setOrder(order);
        });

    }
    private void initBean() throws Exception {
        InitBean initBean = new InitBean();
        initBean.handle();
    }

    /**
     * 执行 实现 ApplicationRunner 和 CommandLineRunner接口的类
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    private void executeRunner() throws Exception {
        registry.forEachSingletonObjects((name,value) -> {
            Class beanClass = value.getClass();
            if(ApplicationRunner.class.isAssignableFrom(beanClass) ||
                    CommandLineRunner.class.isAssignableFrom(beanClass)){
                Method run = beanClass.getMethod("run");
                run.invoke(value);
            }
        });

    }


}
